home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / NR3.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  28KB  |  1,048 lines

  1. /* net/rom level 3 low level processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "iface.h"
  11. #include "timer.h"
  12. #include "arp.h"
  13. #include "slip.h"
  14. #include "ax25.h"
  15. #include "netrom.h"
  16. #include "nr4.h"
  17. #include "lapb.h"
  18. #include "socket.h"
  19. #include "trace.h"
  20. #include "ip.h"
  21.  
  22. static int accept_bc __ARGS((struct ax25_addr *addr,unsigned ifnum));
  23. static struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
  24. static struct nr_bind *find_binding __ARGS((struct nr_bind *list,struct nrnbr_tab *neighbor));
  25. static struct nrnbr_tab *find_nrnbr __ARGS((struct ax25_addr *, unsigned));
  26. static struct nrnf_tab *find_nrnf __ARGS((struct ax25_addr *, unsigned));
  27. static struct nr_bind *find_worst __ARGS((struct nr_bind *list));
  28. static int ismycall __ARGS((struct ax25_addr *addr));
  29. #ifdef    notdef
  30. static char *nr_getroute __ARGS((struct ax25_addr *));
  31. #endif
  32. static int nr_send __ARGS((struct mbuf *bp,struct iface *iface,int32 gateway,int prec,
  33.     int del,int tput,int rel));
  34. static void nr3arp __ARGS((void));
  35.  
  36.  
  37. static struct raw_nr *Raw_nr;
  38.  
  39. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  40. struct ax25_addr Nr_nodebc = {
  41.     'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
  42.     ('0'<<1) | E
  43. } ;
  44.  
  45. struct nriface Nrifaces[NRNUMIFACE] ;
  46. unsigned Nr_numiface ;
  47. struct nrnbr_tab *Nrnbr_tab[NRNUMCHAINS] ;
  48. struct nrroute_tab *Nrroute_tab[NRNUMCHAINS] ;
  49. struct nrnf_tab *Nrnf_tab[NRNUMCHAINS] ;
  50. unsigned Nr_nfmode = NRNF_NOFILTER ;
  51. unsigned short Nr_ttl = 64 ;
  52. static unsigned Obso_init = 6 ;
  53. static unsigned Obso_minbc = 5 ;
  54. static unsigned Nr_maxroutes = 5 ;
  55. static unsigned Nr_autofloor = 1 ;
  56. int Nr_verbose = 0 ;
  57. struct iface *Nr_iface ;
  58.  
  59. /* send a NET/ROM layer 3 datagram */
  60. void
  61. nr3output(dest, data)
  62. struct ax25_addr *dest ;
  63. struct mbuf *data ;
  64. {
  65.     struct nr3hdr n3hdr ;
  66.     struct mbuf *n3b ;
  67.  
  68.     ASSIGN(n3hdr.dest,*dest) ;    /* copy destination field */
  69.     n3hdr.ttl = Nr_ttl ;    /* time to live from initializer parm */
  70.  
  71.     if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
  72.         free_p(data) ;
  73.         return ;
  74.     }
  75.     append(&n3b, data) ;
  76.     /* The null interface indicates that the packet needs to have */
  77.     /* an appropriate source address inserted by nr_route */
  78.     
  79.     nr_route(n3b,NULLAX25) ;
  80. }
  81.  
  82. /* send IP datagrams across a net/rom network connection */
  83. int
  84. nr_send(bp,iface,gateway,prec,del,tput,rel)
  85. struct mbuf *bp ;
  86. struct iface *iface ;
  87. int32 gateway ;
  88. int prec ;
  89. int del ;
  90. int tput ;
  91. int rel ;
  92. {
  93.     struct arp_tab *arp ;
  94.  
  95.     dump(iface,IF_TRACE_OUT,TYPE_IP,bp);
  96.     if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
  97.         free_p(bp) ;    /* drop the packet if no route */
  98.         return -1;
  99.     }
  100.     nr_sendraw(arp->hw_addr, NRPROTO_IP, NRPROTO_IP, bp);
  101.     return 0;
  102. }
  103.  
  104. /* Send arbitrary protocol data on top of a NET/ROM connection */
  105. void
  106. nr_sendraw(dest,family,proto,data)
  107. struct ax25_addr *dest;
  108. unsigned family;
  109. unsigned proto;
  110. struct mbuf *data;
  111. {
  112.     struct mbuf *pbp ;
  113.     struct nr4hdr n4hdr ;
  114.  
  115.     /* Create a "network extension" transport header */
  116.     n4hdr.opcode = NR4OPPID ;
  117.     n4hdr.u.pid.family = family;
  118.     n4hdr.u.pid.proto = proto;
  119.  
  120.      if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
  121.          free_p(data) ;
  122.          return ;
  123.      }
  124.      append(&pbp,data) ;        /* Append the data to that */
  125.     nr3output(dest, pbp) ; /* and pass off to level 3 code */
  126. }
  127.  
  128. /* Arrange for receipt of raw NET/ROM datagrams */
  129. struct raw_nr *
  130. raw_nr(protocol)
  131. char protocol;
  132. {
  133.     register struct raw_nr *rp;
  134.  
  135.     rp = (struct raw_nr *)calloc(1,sizeof(struct raw_nr));
  136.     rp->protocol = protocol;
  137.     rp->next = Raw_nr;
  138.     if(rp->next != NULLRNR)
  139.         rp->next->prev = rp;
  140.     Raw_nr = rp;
  141.     return rp;
  142. }
  143. /* Free a raw NET/ROM descriptor */
  144. void
  145. del_rnr(rpp)
  146. struct raw_nr *rpp;
  147. {
  148.     register struct raw_nr *rp;
  149.  
  150.     /* Do sanity check on arg */
  151.     for(rp = Raw_nr;rp != NULLRNR;rp = rp->next)
  152.         if(rp == rpp)
  153.             break;
  154.     if(rp == NULLRNR)
  155.         return;    /* Doesn't exist */
  156.  
  157.     /* Unlink */
  158.     if(rp->prev != NULLRNR)
  159.         rp->prev->next = rp->next;
  160.     else
  161.         Raw_nr = rp->next;
  162.     if(rp->next != NULLRNR)
  163.         rp->next->prev = rp->prev;
  164.     /* Free resources */
  165.     free_q(&rp->rcvq);
  166.     free((char *)rp);
  167. }
  168.  
  169. /* Figure out if a call is assigned to one of my net/rom
  170.  * interfaces.
  171.  */
  172. static int
  173. ismycall(addr)
  174. struct ax25_addr *addr ;
  175. {
  176.     register int i ;
  177.     int found = 0 ;
  178.     
  179.     for (i = 0 ; i < Nr_numiface ; i++)
  180.         if (addreq((struct ax25_addr *)(Nrifaces[i].iface->hwaddr),
  181.             addr)) {
  182.             found = 1 ;
  183.             break ;
  184.         }
  185.  
  186.     return found ;
  187. }
  188.  
  189.  
  190. /* Route net/rom network layer packets.
  191.  */
  192. void
  193. nr_route(bp, iaxp)
  194. struct mbuf *bp ;                /* network packet */
  195. struct ax25_cb *iaxp ;            /* incoming ax25 control block */
  196. {
  197.     struct nr3hdr n3hdr ;
  198.     struct nr4hdr n4hdr ;
  199.     struct ax25_cb *axp;
  200.     struct ax25 naxhdr ;
  201.     struct ax25_addr neighbor, from ;
  202.     struct mbuf *hbp, *pbp;
  203.     struct raw_nr *rnr;
  204.     register struct nrnbr_tab *np ;
  205.     register struct nrroute_tab *rp ;
  206.     register struct nr_bind *bindp;
  207.     struct iface *iface ;
  208.     unsigned ifnum ;
  209.     
  210.     if (ntohnr3(&n3hdr,&bp) == -1) {
  211.         free_p(bp) ;
  212.         return ;
  213.     }
  214.      /* If this isn't an internally generated network packet,
  215.       * give the router a chance to record a route back to the
  216.       * sender, in case they aren't in the local node's routing
  217.       * table yet.
  218.       */
  219.       if (iaxp != NULLAX25 && ax_lookup(&iaxp->remote) != NULLAXR) {
  220.             
  221.          /* find the interface number */
  222.          for (ifnum = 0 ; ifnum < Nr_numiface ; ifnum++)
  223.              if (iaxp->iface == Nrifaces[ifnum].iface)
  224.                  break ;
  225.  
  226.          if (ifnum == Nr_numiface) {    /* Not a net/rom interface! */
  227.              free_p(bp) ;
  228.              return ;
  229.          }
  230.  
  231.          from = iaxp->remote ;
  232.          from.ssid |= E ;
  233.  
  234.          /* Add (possibly) a zero-quality recorded route via */
  235.          /* the neighbor from which this packet was received */
  236.          /* Note that this doesn't work with digipeated neighbors. */
  237.          
  238.          (void) nr_routeadd("      ",&n3hdr.source,ifnum,0,
  239.          (char *)&from,0,1) ;
  240.     }
  241.  
  242.      /* A packet from me, to me, can only be one thing: */
  243.      /* a horrible routing loop.  This will probably result */
  244.      /* from a bad manual ARP entry, but we should fix these */
  245.      /* obscure errors as we find them. */
  246.      
  247.       if (ismycall(&n3hdr.dest)) {
  248.         /* Toss if from me, or if we can't read the header */
  249.           if (iaxp == NULLAX25 || ntohnr4(&n4hdr,&bp) == -1){
  250.               free_p(bp) ;
  251.         } else if((n4hdr.opcode & NR4OPCODE) == NR4OPPID){
  252.             for(rnr = Raw_nr;rnr!=NULLRNR;rnr = rnr->next){
  253.                 if(rnr->protocol!=n4hdr.u.pid.family ||
  254.                  rnr->protocol != n4hdr.u.pid.proto)
  255.                     continue;
  256.                 /* Duplicate the data portion, and put the
  257.                  * level 3 header back on
  258.                  */
  259.                 dup_p(&pbp,bp,0,len_mbuf(bp));
  260.                 if(pbp != NULLBUF &&
  261.                  (hbp = htonnr3(&n3hdr)) != NULLBUF){
  262.                     append(&hbp,pbp);
  263.                     enqueue(&rnr->rcvq,hbp);
  264.                 } else {
  265.                     free_p(pbp);
  266.                     free_p(hbp);
  267.                 }
  268.             }
  269.             /* IP does not use a NET/ROM level 3 socket */
  270.             if (n4hdr.u.pid.family == NRPROTO_IP
  271.              && n4hdr.u.pid.proto == NRPROTO_IP)
  272.                  ip_route(bp,0) ;
  273.             else         /* we don't do this proto */
  274.                  free_p(bp) ;
  275.         } else {
  276.             /* Must be net/rom transport: */
  277.             nr4input(&n4hdr,bp) ;
  278.         }
  279.         return ;
  280.       }
  281.     if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
  282.         /* no route, drop the packet */
  283.         free_p(bp) ;
  284.         return ;
  285.     }
  286.     if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
  287.         /* This shouldn't happen yet, but might if we add */
  288.         /* dead route detection */
  289.         free_p(bp) ;
  290.         return ;
  291.     }
  292.  
  293.     np = bindp->via ;
  294.     memcpy(neighbor.call,np->call,ALEN) ;
  295.     neighbor.ssid = np->call[ALEN] ;
  296.     iface = Nrifaces[np->iface].iface ;
  297.  
  298.      /* Now check to see if iaxp is null.  That is */
  299.      /* a signal that the packet originates here, */
  300.       /* so we need to insert the callsign of the appropriate  */
  301.       /* interface */
  302.       if (iaxp == NULLAX25)
  303.         memcpy(&n3hdr.source,iface->hwaddr,AXALEN) ;
  304.     
  305.     /* Make sure there is a connection to the neighbor */
  306.     if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
  307.         (axp->state != CONNECTED && axp->state != RECOVERY)) {
  308.         /* Open a new connection or reinitialize old one */
  309.         /* hwaddr has been advanced to point to neighbor + digis */
  310.         atohax25(&naxhdr, np->call, (struct ax25_addr *)iface->hwaddr) ;
  311.         axp = open_ax25(iface,&Mycall,&naxhdr.dest, AX_ACTIVE, Axwindow, s_arcall, s_atcall, s_ascall,-1) ;
  312.         if (axp == NULLAX25) {
  313.             free_p(bp) ;
  314.             return ;
  315.         }
  316.     }
  317.         
  318.     if (--n3hdr.ttl == 0) {    /* the packet's time to live is over! */
  319.         free_p(bp) ;
  320.         return ;
  321.     }
  322.     /* now format network header */
  323.     if ((pbp = htonnr3(&n3hdr)) == NULLBUF) {
  324.         free_p(bp) ;
  325.         return ;
  326.     }
  327.     append(&pbp,bp) ;        /* append data to header */
  328.  
  329.     /* put AX.25 PID on front */
  330.     if((bp = pushdown(pbp,1)) == NULLBUF){
  331.         free_p(pbp) ;
  332.         return ;
  333.     }
  334.     bp->data[0] = PID_NETROM ;
  335.  
  336.     if((pbp = segmenter(bp,axp->paclen)) == NULLBUF){
  337.         free_p(bp);
  338.         return;
  339.     }
  340.     send_ax25(axp,pbp,-1) ;    /* pass it off to ax25 code */
  341. }
  342.     
  343.  
  344. /* Perform a nodes broadcast on interface # ifno in the net/rom
  345.  * interface table.
  346.  */
  347. void 
  348. nr_bcnodes(ifno)
  349. unsigned ifno ;
  350. {
  351.     struct mbuf *hbp, *dbp, *savehdr ;
  352.     struct nrroute_tab *rp ;
  353.     struct nrnbr_tab *np ;
  354.     struct nr_bind * bp ;
  355.     struct nr3dest nrdest ;
  356.     int i, didsend = 0, numdest = 0 ;
  357.     register char *cp ;
  358.     struct iface *axif = Nrifaces[ifno].iface ;
  359.     
  360.     /* prepare the header */
  361.     if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  362.         return ;
  363.         
  364.     hbp->cnt = NR3NODEHL ;    
  365.     
  366.     *hbp->data = NR3NODESIG ;
  367.     memcpy(hbp->data+1,Nrifaces[ifno].alias,ALEN) ;
  368.  
  369.     /* Some people don't want to advertise any routes; they
  370.      * just want to be a terminal node.  In that case we just
  371.      * want to send our call and alias and be done with it.
  372.      */
  373.  
  374.     if (!Nr_verbose) {
  375.         (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  376.                          PID_NETROM, hbp) ;    /* send it */
  377.         return ;
  378.     }
  379.  
  380.     /* make a copy of the header in case we need to send more than */
  381.     /* one packet */
  382.     savehdr = copy_p(hbp,NR3NODEHL) ;
  383.  
  384.     /* now scan through the routing table, finding the best routes */
  385.     /* and their neighbors.  create destination subpackets and append */
  386.     /* them to the header */
  387.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  388.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  389.             /* look for best, non-obsolescent route */
  390.             if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
  391.                 continue ;    /* no non-obsolescent routes found */
  392.             if (bp->quality == 0)    /* this is a loopback route */
  393.                 continue ;            /* we never broadcast these */
  394.             np = bp->via ;
  395.             /* insert best neighbor */
  396.             memcpy(nrdest.neighbor.call,np->call,ALEN) ;
  397.             nrdest.neighbor.ssid = np->call[ALEN] ;
  398.             /* insert destination from route table */
  399.             nrdest.dest = rp->call ;
  400.             /* insert alias from route table */
  401.             strcpy(nrdest.alias,rp->alias) ;
  402.             /* insert quality from binding */
  403.             nrdest.quality = bp->quality ;
  404.             /* create a network format destination subpacket */
  405.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  406.                 free_p(hbp) ;    /* drop the whole idea ... */
  407.                 free_p(savehdr) ;
  408.                 return ;
  409.             }
  410.             append(&hbp,dbp) ;    /* append to header and others */
  411.             /* see if we have appended as many destinations */
  412.             /* as we can fit into a single broadcast.  If we */
  413.             /* have, go ahead and send them out. */
  414.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  415.                 didsend = 1 ;    /* indicate that we did broadcast */
  416.                 numdest = 0 ;    /* reset the destination counter */
  417.                 (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  418.                                  PID_NETROM,
  419.                                  hbp) ;    /* send it */
  420.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  421.             }
  422.         }
  423.     }
  424.  
  425.     /* Now, here is something totally weird.  If our interfaces */
  426.     /* have different callsigns than this one, advertise a very */
  427.     /* high quality route to them.  Is this a good idea?  I don't */
  428.     /* know.  However, it allows us to simulate a bunch of net/roms */
  429.     /* hooked together with a diode matrix coupler. */
  430.     for (i = 0 ; i < Nr_numiface ; i++) {
  431.         if (i == ifno)
  432.             continue ;        /* don't bother with ours */
  433.         cp = Nrifaces[i].iface->hwaddr ;
  434.         if (!addreq((struct ax25_addr *)axif->hwaddr,cp)) {
  435.             /* both destination and neighbor address */
  436.             memcpy(&nrdest.dest,cp,AXALEN) ;
  437.             memcpy(&nrdest.neighbor,cp,AXALEN) ;
  438.             /* alias of the interface */
  439.             strcpy(nrdest.alias,Nrifaces[i].alias) ;
  440.             /* and the very highest quality */
  441.             nrdest.quality = 255 ;
  442.             /* create a network format destination subpacket */
  443.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  444.                 free_p(hbp) ;    /* drop the whole idea ... */
  445.                 free_p(savehdr) ;
  446.                 return ;
  447.             }
  448.             append(&hbp,dbp) ;    /* append to header and others */
  449.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  450.                 didsend = 1 ;    /* indicate that we did broadcast */
  451.                 numdest = 0 ;    /* reset the destination counter */
  452.                 (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  453.                                  PID_NETROM,
  454.                                  hbp) ;    /* send it */
  455.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  456.             }
  457.         }
  458.     }
  459.             
  460.     /* If we have a partly filled packet left over, or we never */
  461.     /* sent one at all, we broadcast: */
  462.     if (!didsend || numdest > 0)
  463.         (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  464.                         PID_NETROM, hbp) ;
  465.  
  466.     free_p(savehdr) ;    /* free the header copy */
  467. }
  468.  
  469.  
  470. /* initialize fake arp entry for netrom */
  471. static void
  472. nr3arp()
  473. {
  474.  
  475.     arp_init(ARP_NETROM,AXALEN,0,0,0,NULLCHAR,psax25,setpath) ;
  476. }
  477.  
  478. /* attach the net/rom interface.  no parms for now. */
  479. int
  480. nr_attach(argc,argv,p)
  481. int argc ;
  482. char *argv[] ;
  483. void *p;
  484. {
  485.     if (Nr_iface != (struct iface *)0) {
  486.         printf("netrom interface already attached\n") ;
  487.         return -1 ;
  488.     }
  489.  
  490.     nr3arp() ;
  491.     
  492.     Nr_iface = (struct iface *)calloc(1,sizeof(struct iface)) ;
  493.     Nr_iface->name = "netrom" ;
  494.     Nr_iface->mtu = NR4MAXINFO ;
  495.     Nr_iface->send = nr_send ;
  496.     Nr_iface->next = Ifaces ;
  497.     Ifaces = Nr_iface ;
  498.     ASSIGN(Nr4user,Mycall);
  499.     return 0 ;
  500. }
  501.  
  502. /* This function checks an ax.25 address and interface number against
  503.  * the filter table and mode, and returns 1 if the address is to be
  504.  * accepted, and 0 if it is to be filtered out.
  505.  */
  506. static int
  507. accept_bc(addr,ifnum)
  508. struct ax25_addr *addr ;
  509. unsigned ifnum ;
  510. {
  511.     struct nrnf_tab *fp ;
  512.  
  513.     if (Nr_nfmode == NRNF_NOFILTER)        /* no filtering in effect */
  514.         return 1 ;
  515.  
  516.     fp = find_nrnf(addr,ifnum) ;        /* look it up */
  517.     
  518.     if ((fp != NULLNRNFTAB && Nr_nfmode == NRNF_ACCEPT)
  519.         || (fp == NULLNRNFTAB && Nr_nfmode == NRNF_REJECT))
  520.         return 1 ;
  521.     else
  522.         return 0 ;
  523. }
  524.  
  525.  
  526. /* receive and process node broadcasts. */
  527. void
  528. nr_nodercv(iface,source,bp)
  529. struct iface *iface ;
  530. struct ax25_addr *source ;
  531. struct mbuf *bp ;
  532. {
  533.     register int ifnum ;
  534.     char bcalias[7] ;
  535.     struct nr3dest ds ;
  536.     char sbuf[AXALEN*3] ;
  537.     
  538.     /* First, see if this is even a net/rom interface: */
  539.     for (ifnum = 0 ; ifnum < Nr_numiface ; ifnum++)
  540.         if (iface == Nrifaces[ifnum].iface)
  541.             break ;
  542.             
  543.     if (ifnum == Nr_numiface) {    /* not in the interface table */
  544.         free_p(bp) ;
  545.         return ;
  546.     }
  547.  
  548.     if (!accept_bc(source,ifnum)) {    /* check against filter */
  549.         free_p(bp) ;
  550.         return ;
  551.     }
  552.     
  553.     /* See if it has a routing broadcast signature: */
  554.     if (uchar(pullchar(&bp)) != NR3NODESIG) {
  555.         free_p(bp) ;
  556.         return ;
  557.     }
  558.  
  559.     /* now try to get the alias */
  560.     if (pullup(&bp,bcalias,ALEN) < ALEN) {
  561.         free_p(bp) ;
  562.         return ;
  563.     }
  564.  
  565.     bcalias[ALEN] = '\0' ;        /* null terminate */
  566.  
  567.     /* copy source address and convert to arp format */
  568.     memcpy(sbuf,source->call,ALEN) ;
  569.     sbuf[ALEN] = (source->ssid | E) ;    /* terminate */
  570.     
  571.     /* enter the neighbor into our routing table */
  572.     if (nr_routeadd(bcalias,source,ifnum,Nrifaces[ifnum].quality,
  573.                     sbuf, 0, 0) == -1) {
  574.         free_p(bp) ;
  575.         return ;
  576.     }
  577.     
  578.     /* we've digested the header; now digest the actual */
  579.     /* routing information */
  580.     while (ntohnrdest(&ds,&bp) != -1) {
  581.         /* ignore routes to me! */
  582.         if (ismycall(&ds.dest))
  583.             continue ;
  584.         /* ignore routes below the minimum quality threshhold */
  585.         if (ds.quality < Nr_autofloor)
  586.             continue ;
  587.         /* set loopback paths to 0 quality */
  588.         if (ismycall(&ds.neighbor))
  589.             ds.quality = 0 ;
  590.         else
  591.             ds.quality = ((ds.quality * Nrifaces[ifnum].quality + 128)
  592.                           / 256) & 0xff ;
  593.         if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0,0)
  594.             == -1)
  595.             break ;
  596.     }
  597.             
  598.     free_p(bp) ;    /* This will free the mbuf if anything fails above */
  599. }
  600.  
  601.  
  602. /* The following are utilities for manipulating the routing table */
  603.  
  604. /* hash function for callsigns.  Look familiar? */
  605. int16
  606. nrhash(s)
  607. struct ax25_addr *s ;
  608. {
  609.     register char x ;
  610.     register int i ;
  611.     register char *cp ;
  612.  
  613.     x = 0 ;
  614.     cp = s->call ;
  615.     for (i = ALEN ; i !=0 ; i--)
  616.         x ^= *cp++ & 0xfe ;
  617.     x ^= s->ssid & SSID ;
  618.     return uchar(x) % NRNUMCHAINS ;
  619. }
  620.  
  621. /* Find a neighbor table entry.  Neighbors are determined by
  622.  * their callsign and the interface number.  This takes care
  623.  * of the case where the same switch or hosts uses the same
  624.  * callsign on two different channels.  This isn't done by
  625.  * net/rom, but it might be done by stations running *our*
  626.  * software.
  627.  */
  628. static struct nrnbr_tab *
  629. find_nrnbr(addr,ifnum)
  630. register struct ax25_addr *addr ;
  631. unsigned ifnum ;
  632. {
  633.     int16 hashval ;
  634.     register struct nrnbr_tab *np ;
  635.     char i_state ;
  636.     struct ax25_addr ncall ;
  637.  
  638.     /* Find appropriate hash chain */
  639.     hashval = nrhash(addr) ;
  640.  
  641.     /* search hash chain */
  642.     i_state = dirps() ;
  643.     for (np = Nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
  644.         memcpy(ncall.call,np->call,ALEN) ;    /* convert first in */
  645.         ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
  646.         if (addreq(&ncall,addr) && np->iface == ifnum) {
  647.             restore(i_state) ;
  648.             return np ;
  649.         }
  650.     }
  651.     restore(i_state) ;
  652.     return NULLNTAB ;
  653. }
  654.  
  655.  
  656. /* Find a route table entry */
  657. struct nrroute_tab *
  658. find_nrroute(addr)
  659. register struct ax25_addr *addr ;
  660. {
  661.     int16 hashval ;
  662.     register struct nrroute_tab *rp ;
  663.     char i_state ;
  664.  
  665.     /* Find appropriate hash chain */
  666.     hashval = nrhash(addr) ;
  667.  
  668.     /* search hash chain */
  669.     i_state = dirps() ;
  670.     for (rp = Nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
  671.         if (addreq(&rp->call,addr)) {
  672.             restore(i_state) ;
  673.             return rp ;
  674.         }
  675.     }
  676.     restore(i_state) ;
  677.     return NULLNRRTAB ;
  678. }
  679.  
  680. /* Try to find the AX.25 address of a node with the given alias.  Return */
  681. /* a pointer to the AX.25 address if found, otherwise NULLAXADDR.  The alias */
  682. /* should be a six character, blank-padded, upper-case string. */
  683.  
  684. struct ax25_addr *
  685. find_nralias(alias)
  686. char *alias ;
  687. {
  688.     int i ;
  689.     register struct nrroute_tab *rp ;
  690.  
  691.     /* Since the route entries are hashed by ax.25 address, we'll */
  692.     /* have to search all the chains */
  693.     
  694.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  695.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next)
  696.             if (strncmp(alias, rp->alias, 6) == 0)
  697.                 return &rp->call ;
  698.  
  699.     /* If we get to here, we're out of luck */
  700.  
  701.     return NULLAXADDR ;
  702. }
  703.  
  704.  
  705. /* Find a binding in a list by its neighbor structure's address */
  706. static struct nr_bind *
  707. find_binding(list,neighbor)
  708. struct nr_bind *list ;
  709. register struct nrnbr_tab *neighbor ;
  710. {
  711.     register struct nr_bind *bp ;
  712.  
  713.     for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
  714.         if (bp->via == neighbor)
  715.             return bp ;
  716.  
  717.     return NULLNRBIND ;
  718. }
  719.  
  720. /* Find the worst quality non-permanent binding in a list */
  721. static
  722. struct nr_bind *
  723. find_worst(list)
  724. struct nr_bind *list ;
  725. {
  726.     register struct nr_bind *bp ;
  727.     struct nr_bind *worst = NULLNRBIND ;
  728.     unsigned minqual = 1000 ;     /* infinity */
  729.  
  730.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  731.         if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  732.             worst = bp ;
  733.             minqual = bp->quality ;
  734.         }
  735.  
  736.     return worst ;
  737. }
  738.  
  739. /* Find the best binding of any sort in a list.  If obso is 1,
  740.  * include entries below the obsolescence threshhold in the
  741.  * search (used when this is called for routing broadcasts).
  742.  * If it is 0, routes below the threshhold are treated as
  743.  * though they don't exist.
  744.  */
  745. static
  746. struct nr_bind *
  747. find_best(list,obso)
  748. struct nr_bind *list ;
  749. unsigned obso ;
  750. {
  751.     register struct nr_bind *bp ;
  752.     struct nr_bind *best = NULLNRBIND ;
  753.     int maxqual = -1 ;    /* negative infinity */
  754.  
  755.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  756.         if ((int)bp->quality > maxqual)
  757.             if (obso || bp->obsocnt >= Obso_minbc) {
  758.                 best = bp ;
  759.                 maxqual = bp->quality ;
  760.             }
  761.  
  762.     return best ;
  763. }
  764.  
  765. /* Add a route to the net/rom routing table */
  766. int
  767. nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent,record)
  768. char *alias ;                /* net/rom node alias, blank-padded and */
  769.                             /* null-terminated */
  770. struct ax25_addr *dest ;    /* destination node callsign */
  771. unsigned ifnum ;            /* net/rom interface number */
  772. unsigned quality ;            /* route quality */
  773. char *neighbor ;            /* neighbor node + 2 digis (max) in arp format */
  774. unsigned permanent ;        /* 1 if route is permanent (hand-entered) */
  775. unsigned record ;            /* 1 if route is a "record route" */
  776. {
  777.     struct nrroute_tab *rp ;
  778.     struct nr_bind *bp ;
  779.     struct nrnbr_tab *np ;
  780.     int16 rhash, nhash ;
  781.     struct ax25_addr ncall ;
  782.  
  783.     /* See if a routing table entry exists for this destination */
  784.     if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
  785.         if ((rp =
  786.              (struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
  787.             == NULLNRRTAB)
  788.             return -1 ;
  789.         else {            /* create a new route table entry */
  790.             strncpy(rp->alias,alias,6) ;
  791.             rp->call = *dest ;
  792.             rhash = nrhash(dest) ;
  793.             rp->next = Nrroute_tab[rhash] ;
  794.             if (rp->next != NULLNRRTAB)
  795.                 rp->next->prev = rp ;
  796.             Nrroute_tab[rhash] = rp ;    /* link at head of hash chain */
  797.         }
  798.      } else if (!record) {
  799.          strncpy(rp->alias,alias,6) ;    /* update the alias */
  800.     }
  801.  
  802.     /* See if an entry exists for this neighbor */
  803.     memcpy(ncall.call,neighbor,ALEN) ;    /* no digis included */
  804.     ncall.ssid = neighbor[ALEN] ;
  805.     if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
  806.         if ((np =
  807.              (struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
  808.              == NULLNTAB) {
  809.             if (rp->num_routes == 0) {    /* we just added to table */
  810.                 Nrroute_tab[rhash] = rp->next ;
  811.                 free((char *)rp) ;                /* so get rid of it */
  812.             }
  813.             return -1 ;
  814.         }
  815.         else {        /* create a new neighbor entry */
  816.             memcpy(np->call,neighbor,3 * AXALEN) ;
  817.             np->iface = ifnum ;
  818.             nhash = nrhash(&ncall) ;
  819.             np->next = Nrnbr_tab[nhash] ;
  820.             if (np->next != NULLNTAB)
  821.                 np->next->prev = np ;
  822.             Nrnbr_tab[nhash] = np ;
  823.         }
  824.     }
  825.     else if (permanent) {        /* force this path to the neighbor */
  826.         memcpy(np->call,neighbor,3 * AXALEN) ;
  827.     }
  828.         
  829.     /* See if there is a binding between the dest and neighbor */
  830.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
  831.         if ((bp =
  832.              (struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
  833.             == NULLNRBIND) {
  834.             if (rp->num_routes == 0) {    /* we just added to table */
  835.                 Nrroute_tab[rhash] = rp->next ;
  836.                 free((char *)rp) ;                /* so get rid of it */
  837.             }
  838.             if (np->refcnt == 0) {        /* we just added it */
  839.                 Nrnbr_tab[nhash] = np->next ;
  840.                 free((char *)np) ;
  841.             }
  842.             return -1 ;
  843.         }
  844.         else {        /* create a new binding and link it in */
  845.             bp->via = np ;    /* goes via this neighbor */
  846.             bp->next = rp->routes ;    /* link into binding chain */
  847.             if (bp->next != NULLNRBIND)
  848.                 bp->next->prev = bp ;
  849.             rp->routes = bp ;
  850.             rp->num_routes++ ;    /* bump route count */
  851.             np->refcnt++ ;        /* bump neighbor ref count */
  852.             bp->quality = quality ;
  853.             bp->obsocnt = Obso_init ;    /* use initial value */
  854.             if (permanent)
  855.                 bp->flags |= NRB_PERMANENT ;
  856.             else if (record)    /* notice permanent overrides record! */
  857.                 bp->flags |= NRB_RECORDED ;
  858.         }
  859.      } else {
  860.          if (permanent) {    /* permanent request trumps all */
  861.              bp->quality = quality ;
  862.              bp->obsocnt = Obso_init ;
  863.              bp->flags |= NRB_PERMANENT ;
  864.              bp->flags &= ~NRB_RECORDED ;    /* perm is not recorded */
  865.          } else if (!(bp->flags & NRB_PERMANENT)) {    /* not permanent */
  866.              if (record) {    /* came from nr_route */
  867.                  if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
  868.                      bp->quality = quality ;
  869.                      bp->obsocnt = Obso_init ; /* freshen recorded routes */
  870.                  }
  871.              } else {        /* came from a routing broadcast */
  872.                  bp->quality = quality ;
  873.                  bp->obsocnt = Obso_init ;
  874.                  bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
  875.              }
  876.          }
  877.     }
  878.  
  879.     /* Now, check to see if we have too many bindings, and drop */
  880.     /* the worst if we do */
  881.     if (rp->num_routes > Nr_maxroutes) {
  882.         /* since find_worst never returns permanent entries, the */
  883.         /* limitation on number of routes is circumvented for    */
  884.         /* permanent routes */
  885.         if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
  886.             memcpy(ncall.call,bp->via->call,ALEN) ;
  887.             ncall.ssid = bp->via->call[ALEN] ;
  888.             nr_routedrop(dest,&ncall,bp->via->iface) ;
  889.         }
  890.     }
  891.  
  892.     return 0 ;
  893. }
  894.  
  895.  
  896. /* Drop a route to dest via neighbor */
  897. int
  898. nr_routedrop(dest,neighbor,ifnum)
  899. struct ax25_addr *dest, *neighbor ;
  900. unsigned ifnum ;
  901. {
  902.     register struct nrroute_tab *rp ;
  903.     register struct nrnbr_tab *np ;
  904.     register struct nr_bind *bp ;
  905.  
  906.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  907.         return -1 ;
  908.  
  909.     if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
  910.         return -1 ;
  911.  
  912.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  913.         return -1 ;
  914.  
  915.     /* drop the binding first */
  916.     if (bp->next != NULLNRBIND)
  917.         bp->next->prev = bp->prev ;
  918.     if (bp->prev != NULLNRBIND)
  919.         bp->prev->next = bp->next ;
  920.     else
  921.         rp->routes = bp->next ;
  922.  
  923.     free((char *)bp) ;
  924.     rp->num_routes-- ;        /* decrement the number of bindings */
  925.     np->refcnt-- ;            /* and the number of neighbor references */
  926.     
  927.     /* now see if we should drop the route table entry */
  928.     if (rp->num_routes == 0) {
  929.         if (rp->next != NULLNRRTAB)
  930.             rp->next->prev = rp->prev ;
  931.         if (rp->prev != NULLNRRTAB)
  932.             rp->prev->next = rp->next ;
  933.         else
  934.             Nrroute_tab[nrhash(dest)] = rp->next ;
  935.  
  936.         free((char *)rp) ;
  937.     }
  938.  
  939.     /* and check to see if this neighbor can be dropped */
  940.     if (np->refcnt == 0) {
  941.         if (np->next != NULLNTAB)
  942.             np->next->prev = np->prev ;
  943.         if (np->prev != NULLNTAB)
  944.             np->prev->next = np->next ;
  945.         else
  946.             Nrnbr_tab[nrhash(neighbor)] = np->next ;
  947.  
  948.         free((char *)np) ;
  949.     }
  950.     
  951.     return 0 ;
  952. }
  953.  
  954. #ifdef    notused
  955. /* Find the best neighbor for destination dest, in arp format */
  956. static char *
  957. nr_getroute(dest)
  958. struct ax25_addr *dest ;
  959. {
  960.     register struct nrroute_tab *rp ;
  961.     register struct nr_bind *bp ;
  962.  
  963.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  964.         return NULLCHAR ;
  965.  
  966.     if ((bp = find_best(rp->routes,1)) == NULLNRBIND)    /* shouldn't happen! */
  967.         return NULLCHAR ;
  968.  
  969.     return bp->via->call ;
  970. }
  971. #endif    /* notused */
  972.  
  973. /* Find an entry in the filter table */
  974. static struct nrnf_tab *
  975. find_nrnf(addr,ifnum)
  976. register struct ax25_addr *addr ;
  977. unsigned ifnum ;
  978. {
  979.     int16 hashval ;
  980.     register struct nrnf_tab *fp ;
  981.  
  982.     /* Find appropriate hash chain */
  983.     hashval = nrhash(addr) ;
  984.  
  985.     /* search hash chain */
  986.     for (fp = Nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
  987.         if (addreq(&fp->neighbor,addr) && fp->iface == ifnum) {
  988.             return fp ;
  989.         }
  990.     }
  991.  
  992.     return NULLNRNFTAB ;
  993. }
  994.  
  995. /* Add an entry to the filter table.  Return 0 on success,
  996.  * -1 on failure
  997.  */
  998. int
  999. nr_nfadd(addr,ifnum)
  1000. struct ax25_addr *addr ;
  1001. unsigned ifnum ;
  1002. {
  1003.     struct nrnf_tab *fp ;
  1004.     int16 hashval ;
  1005.     
  1006.     if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
  1007.         return 0 ;    /* already there; it's a no-op */
  1008.  
  1009.     if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
  1010.         == NULLNRNFTAB)
  1011.         return -1 ;    /* no storage */
  1012.  
  1013.     hashval = nrhash(addr) ;
  1014.     fp->neighbor = *addr ;
  1015.     fp->iface = ifnum ;
  1016.     fp->next = Nrnf_tab[hashval] ;
  1017.     if (fp->next != NULLNRNFTAB)
  1018.         fp->next->prev = fp ;
  1019.     Nrnf_tab[hashval] = fp ;
  1020.  
  1021.     return 0 ;
  1022. }
  1023.  
  1024. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  1025.  * on failure.
  1026.  */
  1027. int
  1028. nr_nfdrop(addr,ifnum)
  1029. struct ax25_addr *addr ;
  1030. unsigned ifnum ;
  1031. {
  1032.     struct nrnf_tab *fp ;
  1033.  
  1034.     if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
  1035.         return -1 ;    /* not in the table */
  1036.  
  1037.     if (fp->next != NULLNRNFTAB)
  1038.         fp->next->prev = fp->prev ;
  1039.     if (fp->prev != NULLNRNFTAB)
  1040.         fp->prev->next = fp->next ;
  1041.     else
  1042.         Nrnf_tab[nrhash(addr)] = fp->next ;
  1043.  
  1044.     free(fp) ;
  1045.  
  1046.     return 0 ;
  1047. }
  1048.